package player;

import helliker.id3.ID3v2FormatException;
import helliker.id3.MP3File;
import helliker.id3.Playlist;
import helliker.id3.PlaylistException;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Paint;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Port;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.basic.BasicProgressBarUI;

public class JavaPlayer extends JWindow implements ActionListener,
		ControllerListener, MouseMotionListener, Runnable {
	private Playlist playlist;
	private Player player = null;
	private JPanel mainPanel = null;
	private JProgressBar progressBar = null, progressBarvolume = null;
	private String fileTitle = "";
	private Thread playThread = null;
	private JSlider slider;
	private JCheckBox checkbox;
	private int itime, iss, imm, volume;
	private Timer timer;
	private String sTime;
	private JButton Random;
	private PlaylistManager manager;
	private boolean Shuffle = false;

	public JavaPlayer() {
		super();
		setSystemVolume(50);
		mainPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 1, 1));
		mainPanel.setBorder(BorderFactory.createRaisedBevelBorder());
		mainPanel.addMouseMotionListener(this);
		Settings.loadSettings();
		//setBounds(Settings.getMainWindowRect());
		setBounds(100, 100, 670, 25);
		getContentPane().add(mainPanel);
		playlist = new Playlist();
		buildToolbar();
		add(mainPanel);
		setVisible(true);
		File playlistFile = new File(Settings.getPlaylistDirectory(),
				Settings.getPlaylistFile());
		if (playlistFile.exists() && playlistFile.isFile()) {
			progressBar.setString("Loading Playlist...");
			try {
				playlist.loadFromFile(playlistFile);
			} catch (IOException ex) {
				errorMessage(ex.getMessage());
			} catch (PlaylistException ex) {
				errorMessage(ex.getMessage());
			}
			progressBar.setString("Current playing song is : ");
			
		}
		setVisible(true);
		//
		slider.setValue((int)(Settings.getSoundVolume()*50));
		manager= new PlaylistManager(this);// Nho Loa
	}

	private void buildToolbar() {
		JButton button;
		// Open Playlist button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Playlist16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.setActionCommand("Open Playlist");
		button.addActionListener(this);
		mainPanel.add(button);
		// Playlist Manager button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Manager16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.setActionCommand("Playlist Manager");
		button.addActionListener(this);
		mainPanel.add(button);
		// Play button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Play16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.setActionCommand("Play");
		button.addActionListener(this);
		mainPanel.add(button);
		// Pause button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Pause16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.addActionListener(this);
		button.setActionCommand("Pause");
		mainPanel.add(button);
		// Stop button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Stop16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.addActionListener(this);
		button.setActionCommand("Stop");
		mainPanel.add(button);
		// Previous button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Previous16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.addActionListener(this);
		button.setActionCommand("Previous");
		mainPanel.add(button);
		// Next button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Next16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.setActionCommand("Next");
		button.addActionListener(this);
		mainPanel.add(button);
		
		// Random button
		Random = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/R1.gif")));
		Random.setPreferredSize(new Dimension(25, 25));
		Random.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				if(Shuffle) {
					Shuffle = false;		
					Random.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/R1.gif")));
				} else {
					Shuffle = true;

					Random.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/R2.gif")));
				}		
			}		
																																			// Bat tat ngau nhien
		});
		mainPanel.add(Random);
		//end
		
		// Progress bar
		progressBar = new JProgressBar();
		progressBar.setPreferredSize(new Dimension(220, 18));
		progressBar.setStringPainted(true);
		progressBar.setFont(new Font("Dialog", Font.BOLD, 10));
		progressBar.setString("");
		mainPanel.add(progressBar);

		// Volume
		slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
		slider.setPreferredSize(new Dimension(100, 20));

		mainPanel.add(slider);
		MyChangeListener lst = new MyChangeListener();
		slider.addChangeListener(lst);
		

		// Check box
		checkbox = new JCheckBox("Mute");
		checkbox.setPreferredSize(new Dimension(70, 20));
		mainPanel.add(checkbox);

		checkbox.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				volume = slider.getValue();
				
				if (checkbox.isSelected() == true) {
					setMuteVolume(true);
					progressBarvolume.setString("Mute");
				} else {
					setMuteVolume(false);
					slider.setValue(volume);
					progressBarvolume.setString("Volume" + " "
							+ Integer.toString(slider.getValue()) + "%");
				}

			}
		});

		// progress bar
		progressBarvolume = new JProgressBar();
		progressBarvolume.setPreferredSize(new Dimension(70, 18));
		progressBarvolume.setStringPainted(true);
		progressBarvolume.setFont(new Font("Dialog", Font.BOLD, 10));
		progressBarvolume.setString("Volume" + " "
				+ Integer.toString(slider.getValue()) + "%");
		progressBarvolume.setValue(50);
		progressBarvolume.setString("50%");
		mainPanel.add(progressBarvolume);

		// Exit button
		button = new JButton(new ImageIcon(getClass().getClassLoader()
				.getResource("icons/Exit16.gif")));
		button.setPreferredSize(new Dimension(20, 20));
		button.addActionListener(this);
		button.setActionCommand("Exit");
		mainPanel.add(button);
		
		// time con` lai. 
		timer = new Timer(1000, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				iss--;
				if (iss >= 0) {
					sTime = Integer.toString(imm) + ":" + Integer.toString(iss);
				} else {
					imm--;
					iss = 59;
					sTime = Integer.toString(imm) + ":" + Integer.toString(iss);
				}
				progressBar.setString("Playing " + fileTitle + " " + sTime);
			}
		});
	}//end
	public void errorMessage(String s) {
		JOptionPane.showMessageDialog(null, s, "Error",
				JOptionPane.INFORMATION_MESSAGE);
	}

	private void exitAction() {
		Settings.setMainWindowRect(getBounds());
		Settings.storeSettings();
		if (player != null) {
			player.removeControllerListener(this);
			player.stop();
			player.close();
			player = null;
		}
		if (playThread == null) {
			playThread = null;
		}
		System.exit(0);
	}

	private void managerAction() {
		if (playlist != null) {
			PlaylistManager manager = new PlaylistManager(this);
			manager.setVisible(true);
		}

	}

	void playlistAction() {
		JFileChooser fileChooser = new JFileChooser(
				Settings.getPlaylistDirectory());
		fileChooser.setMultiSelectionEnabled(true);
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.addChoosableFileFilter(new playlistFilter());
		fileChooser.setAcceptAllFileFilterUsed(true);
		if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
			progressBar.setString("Loading Playlist...");
			playlist = new Playlist();
			try {
				File playlistFile = fileChooser.getSelectedFile();
				playlist.loadFromFile(playlistFile);
				Settings.setPlaylistDirectory(playlistFile.getParent());
				Settings.setPlaylistFile(playlistFile.getName());
			} catch (IOException ex) {
				errorMessage(ex.getMessage());
			} catch (PlaylistException ex) {
				errorMessage(ex.getMessage());
			}
			play();
			progressBar.setString("");
		}
	}

	public Playlist getPlaylist() {
		return playlist;
	}

	public void setPlaylist(Playlist p) {
		playlist = p;
	}

	public Player getPlayer() {
		return player;
	}

	public void play() {
		MP3File mp3File = null;
		int position = Settings.getPlaylistPosition();
		if (playlist.isEmpty() != true) {
			try {
				mp3File = (MP3File) playlist.get(position);
			
				fileTitle = mp3File.getTitle();
				
			} catch (ID3v2FormatException ex) {
				errorMessage(ex.getMessage());
			}
			if (player == null) {
				try {
					File file = new File(mp3File.getPath());
					// defect
					MediaLocator mediaLocator = new MediaLocator(file.toURI()
							.toURL());
					player = Manager.createPlayer(mediaLocator);
					player.addControllerListener(this);
					progressBar.setString("Realizing...");
					player.realize();
				} catch (MalformedURLException ex) {
					errorMessage(ex.getMessage());
				} catch (NoPlayerException ex) {
					errorMessage(ex.getMessage());
				} catch (IOException ex) {
					errorMessage(ex.getMessage());
				}
			} else {
				player.start();
				// progressBar.setString("Playing " + fileTitle);
				timer.start();

			}
		} else {
			errorMessage("Playlist is empty. Please insert new file");
		}
	}

	private void pause() {
		if (player != null) {
			MP3File mp3File = null;
			int position = Settings.getPlaylistPosition();
			try {
				mp3File = (MP3File) playlist.get(position);
				fileTitle = mp3File.getTitle();
				progressBar.setString(fileTitle + " Paused");
			} catch (ID3v2FormatException ex) {
				errorMessage(ex.getMessage());
			}
			player.stop();
			timer.stop();
		}
	}

	public void stop() {
		if (player != null) {
			player.removeControllerListener(this);
			player.stop();
			player.close();
			player = null;

		}
		if (playThread != null) {
			playThread = null;
		}
		progressBar.setString("Stop");
		progressBar.setValue(0);
		timer.stop();
	}

	/**
	 * Play previous song in playlist
	 */
	private void previous() {
		
		PlaylistManager manager = new PlaylistManager(this);	
		int position = Settings.getPlaylistPosition();
		if(position == 0) {
			position=manager.getNumberOfSong();
		}

		position--;		
		Settings.setPlaylistPosition(position);
		if (player != null)
			stop();
		play();
	}

	private void next() {
		PlaylistManager manager = new PlaylistManager(this);		
		int position = Settings.getPlaylistPosition();
		position++;
		if(position == manager.getNumberOfSong()) {
			position=0;
		}

		if(Shuffle) {
			position = (int) (Math.random()*manager.getNumberOfSong());
		}
		Settings.setPlaylistPosition(position);

		if (player != null)
			stop();
		play();
	}

	public static void main(String args[]) {
		new JavaPlayer();
	}

	public void actionPerformed(ActionEvent ev) {
		JButton button = (JButton) ev.getSource();
		boolean test = false;
		String command = button.getActionCommand();
		if (command.equals("Exit"))
			exitAction();
		else if (command.equals("Open Playlist"))
			playlistAction();
		else if (command.equals("Playlist Manager"))
			managerAction();
		else if (command.equals("Play"))
			play();
		
	
		else if (command.equals("Pause"))
			pause();
		else if (command.equals("Stop"))
			stop();
		else if (command.equals("Previous"))
			previous();
		else if (command.equals("Next"))
			next();
		manager.repaint();	
	}

	public void controllerUpdate(ControllerEvent ev) {
		if (ev instanceof RealizeCompleteEvent) {
			player.prefetch();
			progressBar.setString("Prefetching...");
		}
		if (ev instanceof PrefetchCompleteEvent) {
			Time time = player.getDuration();
			progressBar.setMaximum((int) time.getSeconds());

			itime = (int) time.getSeconds();
			imm = itime / 60;
			iss = itime - (imm * 60);

			playThread = new Thread(this);
			playThread.start();
			player.getGainControl().setLevel(1);
			timer.start();
			player.start();
		}
		if (ev instanceof PrefetchCompleteEvent) {
			Time time = player.getDuration();
			progressBar.setMaximum((int) time.getSeconds());
			progressBar.setString("Playing " + fileTitle);
			playThread = new Thread(this);
			playThread.start();
			player.getGainControl().setLevel(1);
			player.start();
		}
		if (ev instanceof EndOfMediaEvent) {
			player.removeControllerListener(this);
			player.stop();
			player.close();
			player = null;
			if (playThread != null) {
				playThread = null;
			}
			progressBar.setValue(0);
			next();
		}
	}

	public void mouseDragged(MouseEvent ev) {
		Point loc = getLocation();
		Point clk = ev.getPoint();
		Point pt = new Point(loc.x + clk.x, loc.y + clk.y);
		setLocation(pt);
	}

	public void mouseMoved(MouseEvent ev) {
	}

	public void run() {
		while (playThread != null) {
			if (player != null) {
	
				Time time = player.getMediaTime();
				progressBar.setValue((int) time.getSeconds());
				try {
					playThread.sleep(500);
				} catch (InterruptedException ex) {
				}
			}
		}
	}

	class playlistFilter extends FileFilter {
		public boolean accept(File file) {
			if (file.isDirectory())
				return true;
			String s = file.getName().toLowerCase();
			if (s.endsWith(".m3u"))
				return true;
			return false;
		}

		public String getDescription() {
			return "Playlist Files";
		}

	}

	class MyChangeListener implements ChangeListener {
		MyChangeListener() {
		}

		public synchronized void stateChanged(ChangeEvent e) {
			final int frequency = slider.getValue();
			progressBarvolume.setString("Volume" + " " + frequency + "%");
			setSystemVolume(frequency);
			progressBarvolume.setValue(frequency);
			progressBarvolume.setForeground(new Color(255, 0, 100 - frequency));
		}
	}

	/*
	 * -1: Can not set mute or unmute 0 : unmute 1 : mute
	 */
	public int setMuteVolume(boolean value) {
		final Port lineOut;
		try {
			if (AudioSystem.isLineSupported(Port.Info.LINE_OUT)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.LINE_OUT);
				lineOut.open();
			} else if (AudioSystem.isLineSupported(Port.Info.HEADPHONE)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.HEADPHONE);
				lineOut.open();
			} else if (AudioSystem.isLineSupported(Port.Info.SPEAKER)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.SPEAKER);
				lineOut.open();
			} else {
				// writeLog("Unable to get Output Port");
				return -1;
			}

			// final FloatControl controlIn =
			// (FloatControl)lineOut.getControl(FloatControl.Type.VOLUME);
			final BooleanControl controlIn = (BooleanControl) lineOut
					.getControl(BooleanControl.Type.MUTE);
			controlIn.setValue(value);
			if (controlIn.getValue()) {
				// showMessage("Volume is mute");
				// jbtnMute.setText("Unmute");
				return 0;
			} else {
				// showMessage("Volume is unmute");
				// jbtnMute.setText("Mute");
				return 1;
			}
		} catch (final Exception e) {
			// writeLog(e + " LINE_OUT");
		}
		return -1;
	}

	// set System Volume
	public void setSystemVolume(final int vol) {
		final Port lineOut;
		try {
			if (AudioSystem.isLineSupported(Port.Info.LINE_OUT)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.LINE_OUT);
				lineOut.open();
			} else if (AudioSystem.isLineSupported(Port.Info.HEADPHONE)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.HEADPHONE);
				lineOut.open();
			} else if (AudioSystem.isLineSupported(Port.Info.SPEAKER)) {
				lineOut = (Port) AudioSystem.getLine(Port.Info.SPEAKER);
				lineOut.open();
			} else {
				// writeLog("Unable to get Output Port");
				return;
			}

			final FloatControl controlIn = (FloatControl) lineOut
					.getControl(FloatControl.Type.VOLUME);

			controlIn.setValue((float) vol / 100);
			final float volume = 100 * (controlIn.getValue() / controlIn
					.getMaximum());
			// showMessage("Volume : "+volume);
		} catch (final Exception e) {
			// writeLog(e + " LINE_OUT");
		}
	}
}